/*
 * @Author: xiaosihan
 * @Date: 2023-02-06 15:22:57
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2024-10-16 21:02:32
 */
import utils from "@utils";
import { clamp, round } from "lodash";
import {
  AmbientLight,
  DirectionalLight,
  DirectionalLightHelper,
  EquirectangularReflectionMapping,
  MeshStandardMaterial,
  PointLight,
  Vector3,
} from "three";
import ThreeBase from "three-base";
import MeshBase from "three-base/MeshBase";
import keyContorls from "three-base/keyContorls";
import threeUtils from "three-base/threeUtils";
import Fountain from "./component3d/Fountain/Fountain";
import Ground from "./component3d/Ground/Ground";
import ManyModelGroup from "./component3d/ManyModelGroup/ManyModelGroup";
import manyDataBuild from "./component3d/ManyModelGroup/manydata_build.json";
import manyDataTree from "./component3d/ManyModelGroup/manydata_tree.json";
import Sky from "./component3d/Sky/Sky";
import publicMaterial from "./publicMaterial";
import { degToRad, smoothstep } from "three/src/math/MathUtils";
import threeLoader from "three-base/threeLoader";
import envJPG from "./img/env.jpg";
import PointText from "./component3d/PointText/PointText";

/**
 *
 *
 * @class HomeRender
 * @extends {ThreeBase}
 */
class HomeRender extends ThreeBase {
  constructor() {
    super();
  }

  // 环境光
  ambientLight = (() => {
    const ambientLight = new AmbientLight("#fff", 0);
    this.scene.add(ambientLight);
    return ambientLight;
  })();

  //点光源
  pointLight = (() => {
    const pointLight = new PointLight("#fff", 1);
    pointLight.position.set(50, 40, 50);
    pointLight.decay = 0;
    pointLight.castShadow = false;
    pointLight.shadow.mapSize.set(1024, 1024);
    pointLight.distance = 1000;
    this.scene.add(pointLight);
    return pointLight;
  })();

  // 方向光
  directionalLight = (() => {
    const directionalLight = new DirectionalLight("#fff", 1);
    directionalLight.position.set(65, 10, 27);
    directionalLight.target.position.set(0, 0, 0);
    directionalLight.castShadow = true;
    directionalLight.shadow.camera.left = -10000;
    directionalLight.shadow.camera.bottom = -10000;
    directionalLight.shadow.camera.top = 10000;
    directionalLight.shadow.camera.right = 10000;
    directionalLight.shadow.camera.far = 10000;
    directionalLight.shadow.bias = -0.00001;
    directionalLight.shadow.mapSize.set(4096, 4096);
    this.scene.add(directionalLight);
    return directionalLight;
  })();

  //方向光
  directionalLightHelper = (() => {
    const directionalLightHelper = new DirectionalLightHelper(
      this.directionalLight
    );
    if (utils.isDev) {
      this.scene.add(directionalLightHelper);
    }
    return directionalLightHelper;
  })();

  init() {
    super.init();
    this.controls.screenSpacePanning = false;
    this.gridHelper.visible = false;
    this.renderer.shadowMap.enabled = true;
    this.renderer.shadowMap.autoUpdate = true;
    // this.autoRender = false;

    // 设置全局环境贴图
    const envMap = threeLoader.getTexture(envJPG);
    envMap.mapping = EquirectangularReflectionMapping;
    this.scene.environment = envMap;

    // 开发模式时还原记录的位置
    if (threeUtils.isDev && localStorage.honghua_lookAt) {
      this.resetLookAt({
        ...JSON.parse(localStorage.honghua_lookAt),
      });
    }

    // 开发模式时记录当前的位置
    if (threeUtils.isDev) {
      this.controls.addEventListener("change", () => {
        localStorage.honghua_lookAt = JSON.stringify(this.getLookAt());
      });
    }

    if (
      threeUtils.isProd ||
      (threeUtils.isDev && !localStorage.honghua_lookAt)
    ) {
      this.setDefaultLook();
    }
  }

  //默认视角
  setDefaultLook() {
    this.resetLookAt({
      center: new Vector3(-18.367, 0, 1.144),
      position: new Vector3(44.324, 65.571, -44.92),
    });
  }

  // 装饰地面
  ground = (() => {
    const ground = new Ground();
    ground.position.set(0, -1, 0);
    ground.setSize(2000, 2000);
    this.scene.add(ground);
    return ground;
  })();

  sky = (() => {
    const sky = new Sky();
    this.scene.add(sky);
    return sky;
  })();

  // 大量的模型组对象 用于处理 大量的树, 路灯 等
  manyModelGroup = (() => {
    const manyModelGroup = new ManyModelGroup();
    manyModelGroup.setDatas([...manyDataTree, ...manyDataBuild]);
    // manyModelGroup.setDatas([...manyDataBuild]);
    // manyModelGroup.setDatas(manyDataTree);
    // manyModelGroup.setDatas(manyDataBuild);
    // manyModelGroup.children.map((o) => {
    //   o.traverseMesh((mesh) => {
    //     mesh.userData = {
    //       cursor: "pointer",
    //       enableEvent: true,
    //     };
    //     mesh.addEventListener("click", (e) => {
    //       console.log(e);
    //     });
    //   });
    // });
    this.scene.add(manyModelGroup);
    return manyModelGroup;
  })();

  // 地板模型
  floorMesh = (() => {
    const floorMesh = new MeshBase("./floor.glb");
    floorMesh.castShadow = true;
    floorMesh.receiveShadow = true;

    floorMesh.addEventListener("loaded", (e: any) => {
      threeUtils.scaleTo(floorMesh, 500);
      threeUtils.center(floorMesh);
      threeUtils.alignBottom(floorMesh, 0);
    });

    floorMesh.traverseMesh((mesh) => {
      //three事件
      mesh.userData = {
        cursor: "pointer",
        enableEvent: false, // 开关地板的点击事件
      };
      mesh.addEventListener("click", (e: any) => {
        console.log(mesh.name);

        const build_url = utils.randArray([
          //   "./other_build/zalou3.glb",
          //   "./other_build/zalou7.glb",
          //   "./other_build/zalou8.glb",
          //   "./other_build/zalou2.glb",
          //   "./other_build/zalou4.glb",
          //   "./other_build/zalou6.glb",
          "./tree3.glb",
        ]);

        //按住ctrlKey是连续添加实例
        if (e.e.ctrlKey) {
          this.manyModelGroup.addData({
            id: utils.uuid(),
            name: "",
            url: build_url,
            interpolation: 10, // 自动按间距插入实例
            position: {
              x: round(e.point.x, 3),
              y: round(e.point.y, 3),
              z: round(e.point.z, 3),
            },
          });
          //按住shiftKey是减少一个数据
        } else if (e.e.shiftKey) {
          this.manyModelGroup.delLatest();
          // 正常添加一个数据
        } else {
          this.manyModelGroup.addData({
            id: utils.uuid(),
            name: "",
            url: build_url,
            position: {
              x: round(e.point.x, 3),
              y: round(e.point.y, 3),
              z: round(e.point.z, 3),
            },
          });
        }
      });
    });
    this.scene.add(floorMesh);
    return floorMesh;
  })();

  cameraPosition = new Vector3();
  cameraCenter = new Vector3();

  // 点位文字(档案楼)
  pointText = (() => {
    const pointText = new PointText("档案楼");
    pointText.position.set(-20, 9, -28);
    this.add(pointText);
    return pointText;
  })();

  //主楼
  //   build1 = (() => {
  //     const build1 = new MeshBase("./wudongfangzi.glb");
  //     build1.castShadow = true;
  //     build1.receiveShadow = true;
  //     build1.addEventListener("loaded", (e: any) => {
  //       build1.rotation.y = degToRad(90);
  //       threeUtils.scaleTo(build1, 254);
  //       threeUtils.center(build1);
  //       threeUtils.alignBottom(build1, 0);
  //       build1.position.set(-6.259, 8.658, 4.288);
  //     });
  //     build1.traverseMesh((mesh) => {
  //       if (["boli"].includes(mesh.name)) {
  //         mesh.material = publicMaterial.glassMat;
  //       } else if (["平面001", "平面002"].includes(mesh.name)) {
  //         mesh.visible = false;
  //       }

  //       (mesh.material as MeshStandardMaterial).roughness = 0;
  //       (mesh.material as MeshStandardMaterial).metalness = 0.36;

  //       if (utils.isDev) {
  //         //three事件
  //         mesh.userData = {
  //           cursor: "pointer",
  //           enableEvent: true,
  //         };

  //         mesh.addEventListener("dbclick", (e) => {
  //           console.log(mesh.name);
  //           utils.editorMaterial(mesh.material as any);
  //         });
  //       }
  //     });

  //     if (utils.isDev) {
  //       keyContorls.addEventListener("change", (e: any) => {
  //         build1.position.add(e.direction);
  //         console.log(
  //           build1.position
  //             .toArray()
  //             .map((v) => round(v, 3))
  //             .join(", ")
  //         );
  //       });
  //     }

  //     this.add(build1);
  //     return build1;
  //   })();

  //喷泉
  //   fountain = (() => {
  //     const fountain = new Fountain();
  //     fountain.position.set(124, 0, 0);
  //     fountain.scale.set(15, 15, 15);
  //     this.scene.add(fountain);
  //     return fountain;
  //   })();

  render(): void {
    super.render();
    this.cameraPosition.copy(this.getCamera().position);
    this.cameraCenter.copy(this.controls.target);
    let d = this.cameraPosition.distanceTo(this.cameraCenter);
    d = clamp(d, 100, 1000);

    this.directionalLight.shadow.bias =
      -Math.pow(10, -4) * (smoothstep(d, 100, 1000) * 9 + 1);

    // 动态修改阴影范围
    this.directionalLight.target.position.copy(this.cameraCenter);
    this.directionalLight.target.updateMatrixWorld();
    this.directionalLight.shadow.camera.left = -d;
    this.directionalLight.shadow.camera.bottom = -d;
    this.directionalLight.shadow.camera.top = d;
    this.directionalLight.shadow.camera.right = d;
    this.directionalLight.position
      .copy(this.cameraCenter)
      .add(new Vector3(d, d, d));
    this.directionalLight.shadow.camera.updateProjectionMatrix();

    this.directionalLightHelper.update();
  }
}

const homeRenderer = (window.homeRenderer = new HomeRender());

export default homeRenderer;
